/************************************************************************

This is a tutorial example that shows how the C++ classes for DMIS can
be used to generate a DMIS input file.  See the Makefile that
accompanies this file for details of how the executable is compiled.

When this code is compiled and run, it prints the following, which is
a DMIS input file for inspecting a hole in a block.

DMISMN/'SIMPLE DMIS program 1',05.2
DISPLY/OFF
FILNAM/'SIMPLE DMIS output 1',05.2
UNITS/MM,ANGDEC
PRCOMP/ON
D(START1)=DATSET/MCS
DID(OUTFILE)=DEVICE/STOR,'C:\SimpleOut1.dmo'
V(NOMACT)=VFORM/NOM,ACT
OPEN/DID(OUTFILE),FDATA,V(NOMACT),OUTPUT
S(PROBE6)=SNSDEF/PROBE,INDEX,POL,0.0,0.0,0.0,0.0,-1.0,50.0,4.0
SNSLCT/SA(PROBE6)
MODE/MAN
TEXT/OPER,'Identify the corner on the top surface of the part where'
TEXT/OPER,'X and Y are the minimum. Measure a point on the top surface'
TEXT/OPER,'of the part as close as possible to this corner.'
F(PT_0)=FEAT/POINT,CART,0.0,0.0,0.0,0.0,0.0,1.0
MEAS/POINT,F(PT_0),1
ENDMES
D(SYS1)=TRANS/XORIG,FA(PT_0),YORIG,FA(PT_0),ZORIG,FA(PT_0)
D(SYS2)=TRANS/ZORIG,-50.0
MODE/PROG,MAN
FEDRAT/POSVEL,MMPS,30.0
GOTO/50.0,50.0,75.0
SNSET/APPRCH,10.0
SNSET/SEARCH,20.0
SNSET/RETRCT,10.0
F(A_CIRCLE)=FEAT/CIRCLE,INNER,CART,50.0,50.0,40.0,0.0,0.0,1.0,50.0
MEAS/CIRCLE,F(A_CIRCLE),4
GOTO/50.0,50.0,40.0
PTMEAS/CART,75.0,50.0,40.0,-1.0,0.0,0.0
PTMEAS/CART,25.0,50.0,40.0,1.0,0.0,0.0
PTMEAS/CART,50.0,75.0,40.0,0.0,-1.0,0.0
PTMEAS/CART,50.0,25.0,40.0,0.0,1.0,0.0
GOTO/50.0,50.0,40.0
ENDMES
GOTO/50.0,50.0,100.0
OUTPUT/FA(A_CIRCLE)
CLOSE/DID(OUTFILE)
ENDFIL

The C++ classes used here are defined in the files dmis.hh and dmis.cc.

In this tutorial, values are hard coded in order to generate the file
shown above. In a real DMIS generator, there would be more utility 
functions like the makeCartPtmeas, makePtGoto, and makeLabel functions
defined here, and values for the utility functions would be obtained
from a user interface.

To prevent name conflicts between your code and code from the NIST
DMIS Test Suite, all of the code in the Test Suite is in the namespace
NDTS. To use the NDTS code, a "namespace NDTS" declaration is needed
at the beginning of your code as shown below. The namespace declaration
lists the NDTS variables and functions that are not in dmis.hh that will
appear in your code. When they are used in your code, they must be
prefixed by NDTS:: . 

The functions in this file are arranged alphabetically.


************************************************************************/

#include <stdio.h>
#include "dmis.hh"

/************************************************************************/

namespace NDTS {
extern FILE * yyin;                                     // in dmisLex.cc
extern int numErrors;                                   // in dmisYACC.cc
extern int numWarnings;                                 // in dmisYACC.cc
extern inputFile * tree;                                // in dmisYACC.cc

void preprocess(char * fileNameIn);                     // in dmisYACC.cc
void resetParser();                                     // in dmisYACC.cc
int yyparse();                                          // in dmisYACC.cc
}

void addItems(std::list<NDTS::dmisItem *> * items);
void buildFile(NDTS::inputFile * theFile);
void fillMeasBlock(NDTS::measBlock_measStm * aMeasBlock);
int main();
NDTS::ptmeasStm * makeCartPtmeas(double x, double y, double z,
				 double i, double j, double k);
NDTS::labelNameCon * makeLabel(char * name);
NDTS::gotoStm * makePtGoto(double x, double y, double z);

/************************************************************************/

/* addItems

Returned Value: none

Called By: buildFile

This populates the list of dmisItems in the middle of the inputFile.
Each comment shows the actual DMIS code being constructed by the lines
of C++ code that follow the comment.

Note that a MEAS block is a single dmisItem that extends from MEAS to
ENDMES.

*/

void addItems(                  /* ARGUMENTS                  */
 std::list<NDTS::dmisItem *> * items) /* list of dmisItems to fill  */
{
  NDTS::measBlock_measStm * aMeasBlock;
  std::list<NDTS::vformItem *> * vformItems;
  std::list<NDTS::snsetItem *> * snsetItems;

  aMeasBlock = new NDTS::measBlock_measStm();
  fillMeasBlock(aMeasBlock);
  vformItems = new std::list<NDTS::vformItem *>;
  vformItems->push_back(new NDTS::vformItem_NOM(0));
  vformItems->push_back(new NDTS::vformItem_ACT(0));

  // DISPLY/OFF
  items->push_back(new NDTS::displyStmOff(new NDTS::displyOff()));

  // FILNAM/ 'SIMPLE DMIS output 1', 05.2
  items->push_back(new NDTS::filnamStm
		   (new NDTS::stringConst("SIMPLE DMIS output 1"),
		    new NDTS::versionTag(5.2)));

  // UNITS/ MM, ANGDEC
  items->push_back(new NDTS::unitsStm(new NDTS::lengthUnit_MM(),
                                new NDTS::angleUnit_ANGDEC(), 0));

  // PRCOMP/ON
  items->push_back(new NDTS::prcompStm(new NDTS::state_ON()));

  // D(START1) = DATSET/MCS
  items->push_back(new NDTS::datsetStm(new NDTS::dLabel(makeLabel("START1")),
                                 new NDTS::datsetMcs()));

  // DID(OUTFILE)=DEVICE/STOR,'C:\SimpleOut1.dmo'
  items->push_back(new NDTS::deviceStm
                   (new NDTS::didLabel(makeLabel("OUTFILE")),
                    new NDTS::deviceMinor_device(new NDTS::device_STOR(),
						 (new NDTS::stringConst
						  ("C:\\SimpleOut1.dmo")))));

  // V(NOMACT)=VFORM/NOM,ACT
  items->push_back(new NDTS::vformStm(new NDTS::vLabel(makeLabel("NOMACT")),
                                vformItems));

  // OPEN/DID(OUTFILE),FDATA, V(NOMACT), OUTPUT
  items->push_back(new NDTS::openStm
                   (new NDTS::openMinor_openFdata
                    (new NDTS::didLabel(makeLabel("OUTFILE")),
                     new NDTS::openFdata_vLabel
		     (new NDTS::vLabel
		      (makeLabel("NOMACT")), new NDTS::outputAccessUnspec()))));

  // S(PROBE6)=SNSDEF/PROBE, INDEX, POL, 0.0, 0.0, 0.0, 0.0, -1.0, 50, 4.0
  items->push_back(new NDTS::snsdefStm
                   (new NDTS::sLabel(makeLabel("PROBE6")),
                    new NDTS::snsdefProbe
		    (new NDTS::snsdefType_INDEX(),
		     new NDTS::probeLocPol
		     (new NDTS::realConst(0.0),
		      new NDTS::realConst(0.0), 
		      new NDTS::vector(new NDTS::realConst(0.0),
				       new NDTS::realConst(0.0),
				       new NDTS::realConst(-1.0)),
		      new NDTS::realConst(50.0)),
		     new NDTS::realConst(4.0), 0)));

  // SNSLCT/SA(PROBE6)
  items->push_back(new NDTS::snslctStmSensor
                   (new NDTS::snslctSensorTip
                    (new NDTS::saLabel(makeLabel("PROBE6")), 0, 0)));

  // MODE/MAN
  items->push_back(new NDTS::modeStm(false, false));

  // TEXT/OPER, 'Identify the corner on the top surface of the part where'
  items->push_back(new NDTS::textStm
                   (new NDTS::textOper
                    (new NDTS::stringConst
           ("Identify the corner on the top surface of the part where"))));

  // TEXT/OPER, 'X and Y are the minimum. Measure a point on the top surface'
  items->push_back(new NDTS::textStm
                   (new NDTS::textOper
                    (new NDTS::stringConst
           ("X and Y are the minimum. Measure a point on the top surface"))));

  // TEXT/OPER, 'of the part as close as possible to this corner.'
  items->push_back(new NDTS::textStm
                   (new NDTS::textOper
                    (new NDTS::stringConst
           ("of the part as close as possible to this corner."))));

  // F(PT_0)=FEAT/POINT, CART, 0,0,0, 0,0,1
  items->push_back(new NDTS::featPointNom
		   (new NDTS::fLabel(makeLabel("PT_0")),
		    new NDTS::featMinorPoint
		    (new NDTS::cartPoint(new NDTS::realConst(0),
					 new NDTS::realConst(0),
					 new NDTS::realConst(0)),
		     new NDTS::vector(new NDTS::realConst(0.0),
				      new NDTS::realConst(0.0),
				      new NDTS::realConst(1.0)))));
  
  // MEAS/POINT,F(PT_0),1
  // ENDMES
  items->push_back(new NDTS::measBlock_measStm
                   (new NDTS::measStm
		    (new NDTS::measMinorPoint(),
		     new NDTS::fLabel(makeLabel("PT_0")),
		     new NDTS::intConst(1)),
                    0, new NDTS::endmesStm()));

  // D(SYS1)=TRANS/XORIG,FA(PT_0),YORIG,FA(PT_0),ZORIG,FA(PT_0)
  items->push_back(new NDTS::transStm
                   (new NDTS::dLabel(makeLabel("SYS1")),
                    new NDTS::transFeature(new NDTS::orig_XORIG(),
                                     new NDTS::faLabel(makeLabel("PT_0"))),
                    new NDTS::transFeature(new NDTS::orig_YORIG(),
                                     new NDTS::faLabel(makeLabel("PT_0"))),
                    new NDTS::transFeature(new NDTS::orig_ZORIG(),
				     new NDTS::faLabel(makeLabel("PT_0")))));

  // D(SYS2)=TRANS/ZORIG,-50
  items->push_back(new NDTS::transStm
                   (new NDTS::dLabel(makeLabel("SYS2")),
                    new NDTS::transValue(new NDTS::orig_ZORIG(),
					 new NDTS::realConst(-50)), 0, 0));

  // MODE/PROG,MAN
  items->push_back(new NDTS::modeStm(false, true));

  // FEDRAT/POSVEL, MMPS, 30
  items->push_back(new NDTS::fedratStm
                   (new NDTS::fedratPos
                    (new NDTS::fedratLinear_MMPS(new NDTS::realConst(30.0)))));

  // GOTO/50.0, 50.0, 75.0
  items->push_back(makePtGoto(50.0, 50.0, 75.0));

  // SNSET/APPRCH, 10.0
  snsetItems = new std::list<NDTS::snsetItem *>;
  snsetItems->push_back(new NDTS::snsetItem_snsetTypeAndValue
                        (new NDTS::snsetTypeAndValue_APPRCH
                         (new NDTS::realConst(10.0))));
  items->push_back(new NDTS::snsetStm(snsetItems));

  // SNSET/SEARCH, 20.0
  snsetItems = new std::list<NDTS::snsetItem *>;
  snsetItems->push_back(new NDTS::snsetItem_snsetTypeAndValue
                        (new NDTS::snsetTypeAndValue_SEARCH
                         (new NDTS::realConst(20.0))));
  items->push_back(new NDTS::snsetStm(snsetItems));

  // SNSET/RETRCT, 10.0
  snsetItems = new std::list<NDTS::snsetItem *>;
  snsetItems->push_back(new NDTS::snsetItem_snsetTypeAndValue
			(new NDTS::snsetTypeAndValue_RETRCT
			 (new NDTS::realConst(10.0))));
  items->push_back(new NDTS::snsetStm(snsetItems));

  // F(A_CIRCLE) = FEAT/CIRCLE,INNER,CART,50.0,50.0,40.0,0.0,0.0,1.0,50.0
  items->push_back(new NDTS::featCircleNom
		   (new NDTS::fLabel(makeLabel("A_CIRCLE")),
		    new NDTS::featMinorCircle
		    (new NDTS::matDir_INNER(),
		     new NDTS::cartPoint(new NDTS::realConst(50),
					 new NDTS::realConst(50),
					 new NDTS::realConst(40)),
		     new NDTS::vector(new NDTS::realConst(0.0),
				      new NDTS::realConst(0.0),
				      new NDTS::realConst(1.0)),
		     new NDTS::realConst(50.0))));

  // see fillMeasBlock
  items->push_back(aMeasBlock);

  // GOTO/ 50.0, 50.0, 100.0
  items->push_back(makePtGoto(50.0, 50.0, 100.0));

  // OUTPUT/FA(A_CIRCLE)
  items->push_back(new NDTS::outputStm
		   (new NDTS::outputFeat1Fa
		    (new NDTS::faLabel(makeLabel("A_CIRCLE")), 0,0)));

  // CLOSE/DID(OUTFILE)
  items->push_back(new NDTS::closeStm
		   (new NDTS::closePlain
		    (new NDTS::didLabel(makeLabel("OUTFILE")))));
}

/************************************************************************/

/* buildFile

Returned Value: none

Called By: main

This builds the input file from DMISMN, everything in the middle, and
ENDFIL.

*/

void buildFile(       /* ARGUMENTS          */
 NDTS::inputFile * theFile) /* inputFile to build */
{
  std::list<NDTS::dmisItem *> * items;

  items = new std::list<NDTS::dmisItem *>;
  addItems(items);

  // DMISMN/'SIMPLE DMIS program 1',05.2
  theFile->set_dmisFirstStatement
    (new NDTS::dmismnStm
     (new NDTS::stringConst("SIMPLE DMIS program 1"),
      new NDTS::versionTag(5.2), 0));

  // see addItems
  theFile->set_dmisItemList(items);

  // ENDFIL
  theFile->set_endfilStm(new NDTS::endfilStm);
}

/************************************************************************/

/* fillMeasBlock

Returned Value: none

Called By: addItems

This constructs the following DMIS code, which is the contents of a
measBlock.

MEAS/CIRCLE,F(A_CIRCLE),4
GOTO/ 50.0, 50.0, 40.0
PTMEAS/CART, 75.0, 50.0, 40.0, -1.0,  0.0, 0.0
PTMEAS/CART, 25.0, 50.0, 40.0,  1.0,  0.0, 0.0
PTMEAS/CART, 50.0, 75.0, 40.0,  0.0, -1.0, 0.0
PTMEAS/CART, 50.0, 25.0, 40.0,  0.0,  1.0, 0.0
GOTO/ 50.0, 50.0, 40.0
ENDMES

*/

void fillMeasBlock(                    /* ARGUMENTS         */
 NDTS::measBlock_measStm * aMeasBlock) /* measBlock to fill */
{
  std::list<NDTS::measBlockItem *> * blockItems;

  blockItems = new std::list<NDTS::measBlockItem *>;
  blockItems->push_back(makePtGoto(50.0, 50.0, 40.0));
  blockItems->push_back(makeCartPtmeas(75.0, 50.0, 40.0, -1.0,  0.0, 0.0));
  blockItems->push_back(makeCartPtmeas(25.0, 50.0, 40.0,  1.0,  0.0, 0.0));
  blockItems->push_back(makeCartPtmeas(50.0, 75.0, 40.0,  0.0, -1.0, 0.0));
  blockItems->push_back(makeCartPtmeas(50.0, 25.0, 40.0,  0.0,  1.0, 0.0));
  blockItems->push_back(makePtGoto(50.0, 50.0, 40.0));
  aMeasBlock->set_measStm(new NDTS::measStm
			  (new NDTS::measMinorPoint(),
			   new NDTS::fLabel(makeLabel("A_CIRCLE")),
			   new NDTS::intConst(4)));
  aMeasBlock->set_measBlockItemList(blockItems);
  aMeasBlock->set_endmesStm(new NDTS::endmesStm());
}

/************************************************************************/

/* main

This main function calls buildFile to populate an inputFile and then calls
the printSelf method of inputFile to do the printing. The printSelf methods
are defined in dmisPrismatic2.cc.

*/

int main()
{
  NDTS::inputFile * theFile;

  theFile = new NDTS::inputFile();
  buildFile(theFile);
  theFile->printSelf();
  return 0;
}

/************************************************************************/

/* makeCartPtmeas

Returned Value: ptmeasStm

Called By:
  fillMeasBlock

This makes a ptmeasStm from the X, Y, and Z values of a point and the
I, J, and K values of a vector.

*/

NDTS::ptmeasStm * makeCartPtmeas( /* ARGUMENTS                              */
 double x,                        /* X value of point                       */
 double y,                        /* Y value of point                       */
 double z,                        /* Z value of point                       */
 double i,                        /* X component of surface normal at point */
 double j,                        /* Y component of surface normal at point */
 double k)                        /* Z component of surface normal at point */
{
  return new NDTS::ptmeasStm(new NDTS::cartPoint(new NDTS::realConst(x),
						 new NDTS::realConst(y),
						 new NDTS::realConst(z)),
			     new NDTS::vector(new NDTS::realConst(i),
					      new NDTS::realConst(j),
					      new NDTS::realConst(k)), 0);

}

/************************************************************************/

/* makeLabel

Returned Value: labelName_1

Called By:
  fillMeasBlock
  addItems

This makes a labelName from a string that is the name.

*/

NDTS::labelNameCon * makeLabel( /* ARGUMENTS                  */
 char * name)                   /* name to put into labelName */
{
  return new NDTS::labelNameCon(new NDTS::labelNameConst(name));
}

/************************************************************************/

/* makePtGoto

Returned Value: gotoStm

Called By:
  fillMeasBlock
  addItems

This makes a gotoStm from the X, Y, and Z values of a point.

*/

NDTS::gotoStm * makePtGoto( /* ARGUMENTS        */
 double x,                  /* X value of point */
 double y,                  /* Y value of point */
 double z)                  /* Z value of point */
{
  return new NDTS::gotoStm(new NDTS::gotoAbsXyz
			   (new NDTS::impCartPoint(new NDTS::realConst(x),
						   new NDTS::realConst(y),
						   new NDTS::realConst(z))));
}

/************************************************************************/

